//
//  BaseWebViewController.swift
//  CommonTools
//
//  Created by xianquan on 2024/3/21.
//

import UIKit
import TYUIKit
import YYText
import WebKit

class WebScript: NSObject, WKScriptMessageHandler {
    
    weak var scriptDelegate: WKScriptMessageHandler?
    
    init(scriptDelegate: WKScriptMessageHandler? = nil) {
        self.scriptDelegate = scriptDelegate
    }
    
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        scriptDelegate?.userContentController(userContentController, didReceive: message)
    }
}

open class XWWebView: UIView {
    
    let debugJsStr = """
                            console.log = (function(oriLogFunc){
                                    return function(str){
                                                oriLogFunc.call(console,str);
                                                window.webkit.messageHandlers.log.postMessage(str);
                                            }
                                    })(console.log);
                        """
    
    
    /// url
    open var urlString = ""
    open var url: URL? {
        webView.url
    }
    /// 要注入的js
    open var jsString = ""
    /// 加载进度条颜色
    open var loadingProgressColor: UIColor = .selectedColor
    /// 是否下拉重新加载
    open var canDownRefresh = false
    /// 是否加载本地文件
    open var isLocal = false
    
    open var enDebug = false {
        didSet{
            if enDebug{
                let jsScript1 = WKUserScript(source: debugJsStr, injectionTime: .atDocumentStart, forMainFrameOnly: false)
                webView.configuration.userContentController.addUserScript(jsScript1)
                addMessage(name: "log")
            }
        }
    }
    
    open var messageHandleCallBack: (WKScriptMessage) -> () = {_ in}
    
    open var urlChangeCallBack: (URL) -> () = {_ in}
    
    open var isShowProgress = false
    /// 是否允许滑动返回
    open var allowsBackForwardNavigationGestures: Bool = true {
        willSet {
            webView.allowsBackForwardNavigationGestures = newValue
        }
    }
    
    private var progressOb: NSKeyValueObservation?
    
    private var titleOb: NSKeyValueObservation?
    
    public var callback: (CallBackType) -> () = {_ in}
    
    private lazy var webView: WKWebView = {[weak self] in
        guard let self = self else {return WKWebView()}
        // 设置WKWebView基本配置信息
        let configuration = WKWebViewConfiguration()
        configuration.preferences = WKPreferences()
        configuration.allowsInlineMediaPlayback = true
        configuration.selectionGranularity = .character
        
        let userContentController = WKUserContentController()

        if !jsString.isEmpty {
            let jsScript = WKUserScript(source: jsString, injectionTime: .atDocumentStart, forMainFrameOnly: false)
            userContentController.addUserScript(jsScript)
        }
        
        configuration.userContentController = userContentController
        
        webView = WKWebView(frame: bounds, configuration: configuration)
        // 设置代理
        webView.uiDelegate = self
        webView.navigationDelegate = self
        
        
        webView.allowsBackForwardNavigationGestures = allowsBackForwardNavigationGestures
        // 是否开启下拉刷新
        if canDownRefresh {
            webView.scrollView.refreshControl = self.refreshControl
        }
        if isShowProgress {
            // 添加进度监听
            progressOb = webView.observe(\.estimatedProgress, options: .new) {[weak self] web, change in
                guard let self = self else {return}
                progress.progress = Float(web.estimatedProgress)
                if progress.progress == 1.0 {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){[weak self] in
                        guard let self = self else {return}
                        progress.isHidden = true
                    }
                }
            }
        }
        
        titleOb = webView.observe(\.title, options: .new) {[weak self] web, change in
            guard let self = self else {return}
            XWLog(value: web.title)
            callback(.title)
        }
        webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
        return webView
    }()
    
    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "URL" {
            if let newURL = change?[.newKey] as? URL {
                urlChangeCallBack(newURL)
            }
        }
    }
    
    public var isContentHidden: Bool {
        set {
            webView.isHidden = newValue
        }
        get {
            webView.isHidden
        }
    }
    
    public var contentView: WKWebView {
        webView
    }
    
    private lazy var refreshControl: UIRefreshControl = {[unowned self] in
        let control = UIRefreshControl()
        control.addBlock(for: .valueChanged) {[unowned self] _ in
            webView.reload()
        }
        return control
    }()
    private lazy var progress: UIProgressView = {[unowned self] in
        let progress = UIProgressView(frame: CGRect(x: 0, y: 0, width: screenWidth(), height: 0.5))
        progress.progressTintColor = loadingProgressColor
        return progress
    }()
    
    private var messageNames: [String] = []
    
    open func addMessage(name: String){
        let proxy = WebScript(scriptDelegate: self)
        webView.configuration.userContentController.add(proxy, name: name)
        messageNames.append(name)
    }
    /// 调用js方法
    open func evaluateJavaScript(name: String, params: Any? = nil, callback: ((_ result: Any?, _ error: Error?) -> ())? = nil){
        var jsString = params == nil ? "iosBridgeObj.\(name)()" : "iosBridgeObj.\(name)(\(params!))"
        if name.contains("document") {
            jsString = name
        }
        XWLog(value: "执行js方法：\(jsString)")
        webView.evaluateJavaScript(jsString) { result, error in
            if let error = error {
                XWLog(value: "js方法\(name) 执行错误：\(error)")
            }
            if let result = result {
                XWLog(value: "js方法执行结果:\(result)")
            }
            callback?(result, error)
        }
    }
    open func load(_ request: URLRequest) {
        webView.load(request)
    }
    /// 加载html字符串
    open func load(htmlString: String) {
//        let str = "<html><body><p>Hello!</p ></body></html>"
        if webView.superview == nil {
            addSubview(webView)
        }
        webView.loadHTMLString(htmlString, baseURL: nil)
    }
    /// 加载webview
    open func loadRequest() {
        addSubview(webView)
        if isShowProgress{
            addSubview(progress)
        }
        
        if isLocal {//加载本地文件
            if urlString.isEmpty {
                return
            }
            let request = URLRequest(url: URL(fileURLWithPath: urlString))
            webView.load(request)
        }
        else //加载线上链接
        {
            if !urlString.hasPrefix("http") {//容错处理 不要忘记plist文件中设置http可访问 App Transport Security Settings
                urlString = "https://\(urlString)"
            }
            if let url = URL(string: urlString){
                let request = URLRequest(url: url)
                webView.load(request)
            }
        }
    }
    
    open var title: String? {
        webView.title
    }
    
    open var canGoBack: Bool {
        webView.canGoBack
    }
    
    open func goBack(){
        webView.goBack()
    }
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        webView.frame = bounds
    }
    

    deinit {
        XWLog(value: "webview销毁了")
        webView.stopLoading()
        webView.uiDelegate = nil
        webView.navigationDelegate = nil
        webView.removeObserver(self, forKeyPath: "URL")
        if #available(iOS 14.0, *) {
            webView.configuration.userContentController.removeAllScriptMessageHandlers()
        } else {
            for name in messageNames {
                webView.configuration.userContentController.removeScriptMessageHandler(forName: name)
            }
        }
    }
}

public extension XWWebView {
    enum CallBackType {
        /// title更新
        case title
        /// 返回按钮变化
        case back
    }
}

extension XWWebView: WKNavigationDelegate {
    public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        
        progress.isHidden = false
        webView.isHidden = false
    }
    
    public func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        callback(.back)
        refreshControl.endRefreshing()
        webView.evaluateJavaScript("window.navigator.userAgent;")
    }
    
    public func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
        
    }
    
    // 返回内容是否允许加载
    public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        decisionHandler(.allow)
    }
    
    //页面加载失败
    public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        webView.isHidden = true
        
    }
}

extension XWWebView: WKUIDelegate {
    
    public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
        completionHandler()
    }
    
    public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }
    
    public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
        completionHandler("")
    }
    
    @available(iOS 15.0, *)
    public func webView(_ webView: WKWebView, requestMediaCapturePermissionFor origin: WKSecurityOrigin, initiatedByFrame frame: WKFrameInfo, type: WKMediaCaptureType, decisionHandler: @escaping (WKPermissionDecision) -> Void) {
        if (type == .microphone) {
            decisionHandler(.grant)
        }
        else {
            decisionHandler(.prompt)
        }
    }
}

extension XWWebView: WKScriptMessageHandler {

    //MARK: WKScriptMessageHandler js 拦截 调用原生方法

    public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        XWLog(value: "拦截到方法名：\(message.name),参数：\(message.body)")
        messageHandleCallBack(message)
    }
}


open class BaseWebViewController: BaseViewController {
    
    /// url
    open var urlString = "" {
        didSet {
            if hasLoadView {
                webView.urlString = urlString
            }
        }
    }
    /// 要注入的js
    open var jsString = ""
    /// 要显示的html
    open var htmlString = ""
    /// 加载进度条颜色
    open var loadingProgressColor: UIColor = .selectedColor
    /// 是否下拉重新加载
    open var canDownRefresh = false
    /// 是否加载本地文件
    open var isLocal = false {
        didSet {
            if hasLoadView {
                webView.isLocal = isLocal
            }
        }
    }
    
    open var openH5Debug = false {
        didSet{
            if openH5Debug{
                webView.enDebug = true
            }
        }
    }
    /// 是否允许滑动返回
    open var allowsBackForwardNavigationGestures: Bool = true {
        willSet {
            webView.allowsBackForwardNavigationGestures = newValue
        }
    }
    
    open var messageHandleCallBack: (WKScriptMessage) -> () = {_ in} {
        didSet {
            webView.messageHandleCallBack = messageHandleCallBack
        }
    }
    
    open var urlChangeCallBack: (URL) -> () = {_ in} {
        didSet {
            webView.urlChangeCallBack = urlChangeCallBack
        }
    }
    
    public lazy var webView: XWWebView = {
        let webView = XWWebView(frame: CGRect(x: 0, y: TY_NaviBarHeight(), width: screenWidth(), height: screenHeight() - TY_NaviBarHeight()))
        webView.jsString = jsString
        webView.urlString = urlString
        webView.isLocal = isLocal
        webView.loadingProgressColor = loadingProgressColor
        webView.canDownRefresh = canDownRefresh
        webView.messageHandleCallBack = messageHandleCallBack
        webView.urlChangeCallBack = urlChangeCallBack
        webView.isShowProgress = true
        view.addSubview(webView)
        
        return webView
    }()
    
    private var closeBtn: UIButton?
    
    open var isShowCloseBtn: Bool{
        true
    }
    
    private var leftBarItems: [UIBarButtonItem] = []
    
    private var hasLoadView = false
    
    open override func loadView() {
        super.loadView()
        hasLoadView = true
    }
    
    open override func viewDidLoad() {
        super.viewDidLoad()
        setTitle("", rightTitle: "", rightImage: "")
        setupUI()
        if htmlString.count > 0 {
            webView.load(htmlString: htmlString)
        }
        else {
            loadRequest()
        }
        
    }
    
    open func addMessage(name: String){
        webView.addMessage(name: name)
    }
    /// 调用js方法
    open func evaluateJavaScript(name: String, params: Any? = nil, callback: ((_ result: Any?, _ error: Error?) -> ())? = nil){
        webView.evaluateJavaScript(name: name, params: params, callback: callback)
    }
    
    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(false, animated: animated)
    }
    
    private func setupUI(){
        view.addSubview(webView)
        webView.callback = {[weak self] type in
            guard let self = self else {return}
            switch type {
            case .title:
                navigationItem.title = webView.title
            case .back:
                closeBtn?.isHidden = !webView.canGoBack || !isShowCloseBtn
                if leftBarItems.isEmpty {
                    return
                }
                if webView.canGoBack {
                    navigationItem.leftBarButtonItems = leftBarItems
                }
                else {
                    navigationItem.leftBarButtonItems = [leftBarItems[0]]
                }
            }
            
        }
        
        if let backBtn = navigationItem.leftBarButtonItem?.customView{
            let closeBtn = UIButton(image: nil, title: "关闭", titleColor: .black3, font: adapt(14).medium, in: nil, frame: CGRect(x: 0, y: 0, width: 44, height: 44))
            closeBtn.contentHorizontalAlignment = .left
            closeBtn.addTarget(self, action: #selector(close), for: .touchUpInside)
            closeBtn.isHidden = true
            self.closeBtn = closeBtn
            let closeItem = UIBarButtonItem(customView: closeBtn)
            backBtn.width = 30
            DispatchQueue.main.asyncAfter(deadline: .now()){[self] in
                let backItem = UIBarButtonItem(customView: backBtn)
                leftBarItems = [backItem, closeItem]
                navigationItem.leftBarButtonItems = leftBarItems
                
            }
        }
        
    }
    
    public var url: URL? {
        webView.url
    }
    
    open func load(_ request: URLRequest) {
        webView.load(request)
    }
    
    open func loadRequest() {
        
        webView.loadRequest()
    }
    
    open func webViewGoBack() {
        if webView.canGoBack {
            webView.goBack()
        }
    }
    
    open override func leftAction(_ sender: UIButton){
        if webView.canGoBack {
            webView.goBack()
        } else {
            close()
        }
    }
    
    @objc public func close() {
        if navigationController?.viewControllers.count ?? 0 > 1 {
            navigationController?.popViewController(animated: true)
        }
        else{
            dismiss(animated: true)
        }
    }
    
    deinit {
        
    }
}
